<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>mcp-proxy</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .config-area {
            height: 500px;
            resize: none;
        }

        .converter-container {
            min-height: 80vh;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
        <a class="navbar-brand" href="#">mcp-proxy</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav me-auto">
                <li class="nav-item">
                    <a class="nav-link active" href="#">Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="https://github.com/TBXark/mcp-proxy" target="_blank">GitHub</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#features">Feature</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<main class="container my-5">
    <div class="row mb-5">
        <div class="col-12 text-center">
            <h1 class="display-4">mcp-proxy</h1>
            <p class="lead">An MCP proxy server that aggregates and serves multiple MCP resource servers through a single HTTP server.</p>
        </div>
    </div>
    <div class="row mb-5">
        <div class="col-8 offset-2">
            <div class="card bg-dark text-white">
                <div class="card-header d-flex align-items-center">
                    <div class="d-flex me-3">
                        <div class="rounded-circle bg-danger me-2" style="width: 12px; height: 12px;"></div>
                        <div class="rounded-circle bg-warning me-2" style="width: 12px; height: 12px;"></div>
                        <div class="rounded-circle bg-success" style="width: 12px; height: 12px;"></div>
                    </div>
                </div>
                <div class="card-body p-0">
                <pre class="m-0 p-3"
                     style="font-family: monospace; background-color: #1e1e1e; border-radius: 0 0 0.375rem 0.375rem;">
<code class="text-white"><span class="text-success">$</span> docker run -d -p 9090:9090 -v ./config.json:/config/config.json ghcr.io/tbxark/mcp-proxy:latest
</code></pre>
                </div>
            </div>
        </div>
    </div>
    <div class="row mb-5">
        <div class="col-12 text-center">
            <p class="lead">Convert the configuration of <strong>mcp-proxy</strong> to the configuration for Claude.</p>
        </div>
    </div>
    <div class="row converter-container">
        <div class="col-md-6">
            <div class="card h-100">
                <div class="card-header bg-primary text-white">
                    <h5 class="mb-0">mcp-proxy</h5>
                </div>
                <div class="card-body">
                    <textarea id="fromConfig" class="form-control config-area"
                              placeholder="Paste mcp-proxy configuration..."></textarea>
                </div>
                <div class="card-footer">
                    <button id="convertBtn" class="btn btn-primary w-100">convert →</button>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card h-100">
                <div class="card-header bg-warning text-white">
                    <h5 class="mb-0">Claude</h5>
                </div>
                <div class="card-body">
                    <textarea id="claudeConfig" class="form-control config-area"
                              placeholder="The configuration of the converted version will be displayed here...."
                              readonly></textarea>
                </div>
                <div class="card-footer">
                    <button id="copyBtn" class="btn btn-warning w-100">copy</button>
                </div>
            </div>
        </div>
    </div>
    <div class="row mt-5" id="features">
        <div class="col-12">
            <h2 class="mb-4">Features</h2>
            <div class="accordion" id="featuresAccordion">
                <div class="accordion-item">
                    <h2 class="accordion-header">
                        <button class="accordion-button" type="button" data-bs-toggle="collapse"
                                data-bs-target="#feature1">
                            Proxy Multiple MCP Clients
                        </button>
                    </h2>
                    <div id="feature1" class="accordion-collapse collapse show" data-bs-parent="#featuresAccordion">
                        <div class="accordion-body">
                            Connects to multiple MCP resource servers and aggregates their tools and capabilities.
                        </div>
                    </div>
                </div>
                <div class="accordion-item">
                    <h2 class="accordion-header">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
                                data-bs-target="#feature2">
                            SSE Support
                        </button>
                    </h2>
                    <div id="feature2" class="accordion-collapse collapse" data-bs-parent="#featuresAccordion">
                        <div class="accordion-body">
                            Provides an SSE (Server-Sent Events) server for real-time updates.
                        </div>
                    </div>
                </div>
                <div class="accordion-item">
                    <h2 class="accordion-header">
                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
                                data-bs-target="#feature3">
                            Flexible Configuration
                        </button>
                    </h2>
                    <div id="feature3" class="accordion-collapse collapse" data-bs-parent="#featuresAccordion">
                        <div class="accordion-body">
                            Supports multiple client types (stdio, sse or streamable-http) with customizable settings.
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</main>
<footer class="bg-dark text-white py-4 mt-5">
    <div class="container">
        <div class="row">
            <div class="col-md-6">
                <h5>mcp-proxy</h5>
            </div>
            <div class="col-md-6 text-md-end">
                <a href="https://github.com/TBXark/mcp-proxy" class="text-white me-3" target="_blank">GitHub</a>
                <a href="https://github.com/TBXark/mcp-proxy/blob/master/LICENSE" class="text-white" target="_blank">MIT
                    LICENSE</a>
            </div>
        </div>
    </div>
</footer>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
    document.getElementById('convertBtn').addEventListener('click', function () {
        try {
            const fromConfig = JSON.parse(document.getElementById('fromConfig').value);
            const claudeConfig = convertConfig(fromConfig);
            document.getElementById('claudeConfig').value = JSON.stringify(claudeConfig, null, 2);
        } catch (e) {
            alert('Configuration conversion failed:' + e.message);
        }
    });

    document.getElementById('copyBtn').addEventListener('click', function () {
        const claudeConfig = document.getElementById('claudeConfig');
        claudeConfig.select();
        document.execCommand('copy');
        alert('Configuration has been copied to the clipboard.');
    });

    function convertConfig(fromConfig) {
        const claudeConfig = {
            mcpServers: {}
        };
        const options = fromConfig?.mcpProxy?.options ?? {};
        const baseURL = fromConfig?.mcpProxy?.baseURL;
        const mcpServers = fromConfig?.mcpServers ?? {};
        if (!baseURL || !isValidUrl(baseURL)) {
            console.error('Invalid or missing baseURL in mcpProxy configuration');
            return claudeConfig;
        }
        try {
            const baseUrlObj = new URL(baseURL);
            for (const key of Object.keys(mcpServers)) {
                const url = new URL(baseUrlObj);
                url.pathname = `${url.pathname.replace(/\/+$/, '')}/${key}/sse`.replace(/\/+/g, '/');
                const server = {
                    url: url.toString()
                };
                const token = mcpServers[key]?.options?.authTokens?.[0] ?? options?.authTokens?.[0];
                if (token) {
                    server.headers = {
                        Authorization: token
                    };
                }

                claudeConfig.mcpServers[key] = server;
            }
        } catch (error) {
            console.error('Error processing URL configuration:', error);
        }

        return claudeConfig;
    }

    function isValidUrl(urlString) {
        try {
            new URL(urlString);
            return true;
        } catch (error) {
            return false;
        }
    }

    async function main() {
        const fromConfig = await fetch("https://raw.githubusercontent.com/TBXark/mcp-proxy/refs/heads/master/config.json").then(r => r.text())
        document.getElementById('fromConfig').value = fromConfig;
        const claudeConfig = convertConfig(JSON.parse(fromConfig));
        document.getElementById('claudeConfig').value = JSON.stringify(claudeConfig, null, 2);
    }

    main().catch(console.error);
</script>
</body>
</html>
